#pragma once

#include "vec3.h"

OPEN_JLIB_NS


struct Box3 {

  Vec3 min, max;

  inline Box3 () noexcept = default;
  inline Box3 (f32 minx, f32 miny, f32 minz, f32 maxx, f32 maxy, f32 maxz) noexcept : min(minx, miny, minz), max(maxx, maxy, maxz) {
  }
  inline Box3 (Vec3 min, Vec3 max) noexcept : min(min), max(max) {
  }
  inline Box3 (const f32 *m) noexcept : min(m), max(m+3) {
  }


  inline Box3& operator&= (Box3 v) noexcept {
    min = Vec3::max(min, v.min);
    max = Vec3::min(max, v.max);
    return *this;
  }
  inline Box3& operator|= (Box3 v) noexcept {
    min = Vec3::min(min, v.min);
    max = Vec3::max(max, v.max);
    return *this;
  }


  inline Box3 operator& (Box3 v) const noexcept {
    return {
      Vec3::max(min, v.min),
      Vec3::min(max, v.max),
    };
  }
  inline Box3 operator| (Box3 v) const noexcept {
    return {
      Vec3::min(min, v.min),
      Vec3::max(max, v.max),
    };
  }


  inline Vec3 operator~ () const noexcept {
    return max - min;
  }


  inline f32 x () const noexcept {
    return min.p[0];
  }
  inline f32 y () const noexcept {
    return min.p[1];
  }
  inline f32 z () const noexcept {
    return min.p[2];
  }
  inline f32 X () const noexcept {
    return max.p[0];
  }
  inline f32 Y () const noexcept {
    return max.p[1];
  }
  inline f32 Z () const noexcept {
    return max.p[2];
  }


  inline Vec3 xyz () const noexcept {
    return min;
  }
  inline Vec3 xyZ () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[2], %[src].s[2])"
    : [dst]"=x"(r): "[dst]"(min), [src]"x"(max));
    return r;
  }
  inline Vec3 xYz () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[1], %[src].s[1])"
    : [dst]"=x"(r): "[dst]"(min), [src]"x"(max));
    return r;
  }
  inline Vec3 xYZ () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[0], %[src].s[0])"
    : [dst]"=x"(r): "[dst]"(max), [src]"x"(min));
    return r;
  }
  inline Vec3 Xyz () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[0], %[src].s[0])"
    : [dst]"=x"(r): "[dst]"(min), [src]"x"(max));
    return r;
  }
  inline Vec3 XyZ () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[1], %[src].s[1])"
    : [dst]"=x"(r): "[dst]"(max), [src]"x"(min));
    return r;
  }
  inline Vec3 XYz () const noexcept {
    f32v4 r;
    asm volatile (R"(
    ins %[dst].s[2], %[src].s[2])"
    : [dst]"=x"(r): "[dst]"(max), [src]"x"(min));
    return r;
  }
  inline Vec3 XYZ () const noexcept {
    return max;
  }


  inline bool contains (Vec3 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    eor %[imm].16b, %[imm].16b, %[imm].16b
    fcmgt %[tp0].4s, %[op1].4s, %[op3].4s
    fcmgt %[tp1].4s, %[op3].4s, %[op2].4s
    ins %[tp0].s[3], %[imm].s[3]
    ins %[tp1].s[3], %[imm].s[3]
    addv %s[tp0], %[tp0].4s
    addv %s[tp1], %[tp1].4s
    add %s[dst], %s[tp0], %s[tp1])"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1)
    : [op1]"x"(min.p), [op2]"x"(max.p), [op3]"x"(v.p));
    return r == 0;
  }
  inline bool contains (Box3 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    eor %[imm].16b, %[imm].16b, %[imm].16b
    fcmgt %[tp0].4s, %[op1].4s, %[op3].4s
    fcmgt %[tp1].4s, %[op4].4s, %[op2].4s
    ins %[tp0].s[3], %[imm].s[3]
    ins %[tp1].s[3], %[imm].s[3]
    addv %s[tp0], %[tp0].4s
    addv %s[tp1], %[tp1].4s
    add %s[dst], %s[tp0], %s[tp1])"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1)
    : [op1]"x"(min.p), [op2]"x"(max.p), [op3]"x"(v.min.p), [op4]"x"(v.max.p));
    return r == 0;
  }
  inline bool intersect (Box3 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    eor %[imm].16b, %[imm].16b, %[imm].16b
    fcmge %[tp0].4s, %[op1].4s, %[op4].4s
    fcmge %[tp1].4s, %[op3].4s, %[op2].4s
    ins %[tp0].s[3], %[imm].s[3]
    ins %[tp1].s[3], %[imm].s[3]
    addv %s[tp0], %[tp0].4s
    addv %s[tp1], %[tp1].4s
    add %s[dst], %s[tp0], %s[tp1])"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1)
    : [op1]"x"(min.p), [op2]"x"(max.p), [op3]"x"(v.min.p), [op4]"x"(v.max.p));
    return r == 0;
  }
};


CLOSE_JLIB_NS